<!DOCTYPE html>



  


<html class="theme-next pisces use-motion" lang="">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/blog/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/blog/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/blog/css/main.css?v=5.1.4" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/blog/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/blog/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/blog/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/blog/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="Hexo, NexT" />










<meta name="description" content="###注解处理器(Annotation Processor) 注解处理器是javac的一个工具，它用来在编译时扫描和处理注解（Annotation）。你可以自定义注解，并注册到相应的注解处理器，由注解处理器来处理你的注解。一个注解的注解处理器，以Java代码（或者编译过的字节码）作为输入，生成文件（通常是.java文件）作为输出。这些生成的Java代码是在生成的.java文件中，所以你不能修改已经">
<meta name="keywords" content="Android、iOS、Web、React Native">
<meta property="og:type" content="article">
<meta property="og:title" content="Android-自定义注解之编译时注解(RetenttionPolicy-CLASS)">
<meta property="og:url" content="http://yoursite.com/blog/2018/08/06/Android/Android-自定义注解之编译时注解(RetenttionPolicy-CLASS)/index.html">
<meta property="og:site_name" content="凌浩雨_博客">
<meta property="og:description" content="###注解处理器(Annotation Processor) 注解处理器是javac的一个工具，它用来在编译时扫描和处理注解（Annotation）。你可以自定义注解，并注册到相应的注解处理器，由注解处理器来处理你的注解。一个注解的注解处理器，以Java代码（或者编译过的字节码）作为输入，生成文件（通常是.java文件）作为输出。这些生成的Java代码是在生成的.java文件中，所以你不能修改已经">
<meta property="og:locale" content="default">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/3110861-92fa822d019f4528.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/3110861-f8218ffbfdb886dc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/3110861-02a597f8b623c514.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/3110861-eb734c92ab62f21d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/3110861-a4af55bfda5cfab3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/3110861-4a8aa7b8292d629e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:updated_time" content="2018-08-06T11:23:23.348Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Android-自定义注解之编译时注解(RetenttionPolicy-CLASS)">
<meta name="twitter:description" content="###注解处理器(Annotation Processor) 注解处理器是javac的一个工具，它用来在编译时扫描和处理注解（Annotation）。你可以自定义注解，并注册到相应的注解处理器，由注解处理器来处理你的注解。一个注解的注解处理器，以Java代码（或者编译过的字节码）作为输入，生成文件（通常是.java文件）作为输出。这些生成的Java代码是在生成的.java文件中，所以你不能修改已经">
<meta name="twitter:image" content="http://upload-images.jianshu.io/upload_images/3110861-92fa822d019f4528.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/blog/',
    scheme: 'Pisces',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: 'Author'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://yoursite.com/blog/2018/08/06/Android/Android-自定义注解之编译时注解(RetenttionPolicy-CLASS)/"/>





  <title>Android-自定义注解之编译时注解(RetenttionPolicy-CLASS) | 凌浩雨_博客</title>
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="default">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/blog/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">凌浩雨_博客</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/blog/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            Home
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/blog/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            Archives
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/blog/blog/2018/08/06/Android/Android-自定义注解之编译时注解(RetenttionPolicy-CLASS)/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="凌浩雨">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/blog/images/avatar.jpeg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="凌浩雨_博客">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">Android-自定义注解之编译时注解(RetenttionPolicy-CLASS)</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-08-06T18:01:38+08:00">
                2018-08-06
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p>###注解处理器(Annotation Processor)</p>
<p>注解处理器是javac的一个工具，它用来在编译时扫描和处理注解（Annotation）。你可以自定义注解，并注册到相应的注解处理器，由注解处理器来处理你的注解。一个注解的注解处理器，以Java代码（或者编译过的字节码）作为输入，生成文件（通常是.java文件）作为输出。这些生成的Java代码是在生成的.java文件中，所以你不能修改已经存在的Java类，例如向已有的类中添加方法。这些生成的Java文件，会同其他普通的手动编写的Java源代码一样被javac编译。</p>
<a id="more"></a>
<p>RetentionPolicy.CLASS：注解被保留到class文件，但jvm加载class文件时候被遗弃，这是默认的生命周期；</p>
<p>####1. 新建两个Module<br>File-&gt;New-&gt;New Module…-&gt;Java Library，填写好Library name和Java class name后点击完成。<br>注意，这里必须为Java库，不然会找不到javax包下的相关资源。<br><img src="http://upload-images.jianshu.io/upload_images/3110861-92fa822d019f4528.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图1.png"></p>
<p>其中annations是存放注解的，processors是存放注解处理器的。</p>
<p>####2. 新建编译时注解<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * 编译时注解</span><br><span class="line"> */</span><br><span class="line">@Target(ElementType.TYPE)</span><br><span class="line">@Retention(RetentionPolicy.CLASS)</span><br><span class="line">public @interface CustomAnnation &#123;</span><br><span class="line">    String value();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>####3. 定义注解处理器<br>定义一个注解处理器 CustomProcessor ，每一个处理器都是继承于AbstractProcessor，并要求必须复写 process() 方法，通常我们使用复写以下4个方法：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * 每一个注解处理器类都必须有一个空的构造函数，默认不写就行</span><br><span class="line"> */</span><br><span class="line">public class CustomProcessor extends AbstractProcessor&#123;</span><br><span class="line">    /**</span><br><span class="line">     * init()方法会被注解处理器工具调用，并输入ProcessingEnvironment参数。</span><br><span class="line">     * ProcessingEnvironment 提供很多有用的工具类Elements，Types和Filter</span><br><span class="line">     * @param processingEnvironment 提供给process用来访问工具框架的环境</span><br><span class="line">     */</span><br><span class="line">    @Override</span><br><span class="line">    public synchronized void init(ProcessingEnvironment processingEnvironment) &#123;</span><br><span class="line">        super.init(processingEnvironment);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 相当于每个处理器的主函数main()，在这里写扫描、评估和处理注解的代码，以及生成java文件。</span><br><span class="line">     * 输入参数RoundEnvironment可以查询出包含特定注解的被注解元素</span><br><span class="line">     * @param set 请求处理注解类型</span><br><span class="line">     * @param roundEnvironment 有关当前和以前的信息环境</span><br><span class="line">     * @return 返回true，则这些注解已声明并且不要求后续Processor处理他们;</span><br><span class="line">     *          返回false，则这些注解未声明并且可能要求后续Processor处理他们;</span><br><span class="line">     */</span><br><span class="line">    @Override</span><br><span class="line">    public boolean process(Set&lt;? extends TypeElement&gt; set, RoundEnvironment roundEnvironment) &#123;</span><br><span class="line">        return false;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 这里必须指定，这个注解处理器是注册给那个注解的。</span><br><span class="line">     * 注意：它的返回值是一个字符串的集合，包含本处理器想要处理注解的注解类型的合法全程。</span><br><span class="line">     * @return 注解器所支持的注解类型集合，如果没有这样的类型，则返回一个空集合。</span><br><span class="line">     */</span><br><span class="line">    @Override</span><br><span class="line">    public Set&lt;String&gt; getSupportedAnnotationTypes() &#123;</span><br><span class="line">        Set&lt;String&gt; annotations = new LinkedHashSet&lt;&gt;();</span><br><span class="line">        annotations.add(CustomAnnation.class.getCanonicalName());</span><br><span class="line">        return annotations;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 指定Java版本，通常这里使用SourceVersion.latestSupported(),</span><br><span class="line">     * 默认返回SourceVersion.RELEASE_6</span><br><span class="line">     * @return 使用的Java版本</span><br><span class="line">     */</span><br><span class="line">    @Override</span><br><span class="line">    public SourceVersion getSupportedSourceVersion() &#123;</span><br><span class="line">        return SourceVersion.latestSupported();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>也可以使用注解的方式来指定Java版本和注解类型<br><img src="http://upload-images.jianshu.io/upload_images/3110861-f8218ffbfdb886dc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图2.png"></p>
<p>####4. 添加注解的处理<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * 相当于每个处理器的主函数main()，在这里写扫描、评估和处理注解的代码，以及生成java文件。</span><br><span class="line"> * 输入参数RoundEnvironment可以查询出包含特定注解的被注解元素</span><br><span class="line"> * @param set 请求处理注解类型</span><br><span class="line"> * @param roundEnvironment 有关当前和以前的信息环境</span><br><span class="line"> * @return 返回true，则这些注解已声明并且不要求后续Processor处理他们;</span><br><span class="line"> *          返回false，则这些注解未声明并且可能要求后续Processor处理他们;</span><br><span class="line"> */</span><br><span class="line">@Override</span><br><span class="line">public boolean process(Set&lt;? extends TypeElement&gt; set, RoundEnvironment roundEnvironment) &#123;</span><br><span class="line">    // roundEnvironment.getElementsAnnotatedWith(CustomAnnotation.class)返回使用给定的注解类型的元素</span><br><span class="line">    for (Element element : roundEnvironment.getElementsAnnotatedWith(CustomAnnotation.class)) &#123;</span><br><span class="line">        System.out.println(&quot;----------------------------------&quot;);</span><br><span class="line">        // 判断元素的类型为Class</span><br><span class="line">        if (element.getKind() == ElementKind.CLASS) &#123;</span><br><span class="line">            // 显示转换元素类型</span><br><span class="line">            TypeElement typeElement = (TypeElement) element;</span><br><span class="line">            // 输出元素名称</span><br><span class="line">            System.out.println(typeElement.getSimpleName());</span><br><span class="line">            // 输出注解属性值</span><br><span class="line">            System.out.println(typeElement.getAnnotation(CustomAnnotation.class).value());</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(&quot;----------------------------------&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    return false;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>####5. 注解处理器配置<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">1、在 processors 库的 main 目录下新建 resources 资源文件夹；</span><br><span class="line">2、在 resources文件夹下建立 META-INF/services 目录文件夹；</span><br><span class="line">3、在 META-INF/services 目录文件夹下创建 javax.annotation.processing.Processor 文件；</span><br><span class="line">4、在 javax.annotation.processing.Processor 文件写入注解处理器的全称，包括包路径；</span><br></pre></td></tr></table></figure></p>
<p>项目结构：<br><img src="http://upload-images.jianshu.io/upload_images/3110861-02a597f8b623c514.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图3.png"></p>
<p>####6. 使用<br>主Module依赖annotations和processors两个moudle，然后编译，如果未打印出结果，则Build-&gt;ReBuild或者Build-&gt;Clean Project-&gt;Make Project.<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">@CustomAnnotation(&quot;Hello World&quot;)</span><br><span class="line">public class MainActivity extends AppCompatActivity &#123;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    protected void onCreate(Bundle savedInstanceState) &#123;</span><br><span class="line">        super.onCreate(savedInstanceState);</span><br><span class="line">        setContentView(R.layout.activity_main);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>####7. 打印结果<br><img src="http://upload-images.jianshu.io/upload_images/3110861-eb734c92ab62f21d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图4.png"></p>
<p>####8.  存在的问题<br>我们的主项目中引用了 processors 库，但注解处理器只在编译处理期间需要用到，编译处理完后就没有实际作用了，而主项目添加了这个库会引入很多不必要的文件，为了处理这个问题我们需要引入个插件<a href="https://bitbucket.org/hvisser/android-apt" target="_blank" rel="noopener">android-apt</a>，它能很好地处理这个问题。</p>
<p>####9. AutoService<br>AutoService注解处理器是Google开发的，用来生成 META-INF/services/javax.annotation.processing.Processor 文件的，你只需要在你定义的注解处理器上添加 @AutoService(Processor.class) 就可以了，简直不能再方便了。</p>
<ul>
<li><p>依赖AutoService库，在processors的build.gradle文件中添加一下依赖，并同步工程。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">compile &apos;com.google.auto.service:auto-service:1.0-rc2&apos;</span><br></pre></td></tr></table></figure>
</li>
<li><p>使用<br><img src="http://upload-images.jianshu.io/upload_images/3110861-a4af55bfda5cfab3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图5.png"></p>
</li>
</ul>
<p>####10. 问题<br>这时重新Make下工程也能看到同样的输出信息了。但是如果你编译生成APK时，可能会出现文件重复的问题。解决办法是在主项目的 <strong>build.gradle</strong> 加上这么一段：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">packagingOptions &#123;  </span><br><span class="line">   exclude &apos;META-INF/services/javax.annotation.processing.Processor&apos;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>这样就不会报错了，这是其中的一个解决方法，还有个更好的解决方法就是用上面提到的<a href="https://bitbucket.org/hvisser/android-apt" target="_blank" rel="noopener">android-apt</a>了</p>
<p>####11. Android-apt<br>官网有这么一段描述：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">The android-apt plugin assists in working with annotation processors in combination with Android Studio. It has two purposes:</span><br><span class="line">1、Allow to configure a compile time only annotation processor as a dependency, not including the artifact in the final APK or library</span><br><span class="line">2、Set up the source paths so that code that is generated from the annotation processor is correctly picked up by Android Studio</span><br></pre></td></tr></table></figure></p>
<p>大体来讲它有两个作用：<br>能在编译时期去依赖注解处理器并进行工作，但在生成 APK 时不会包含任何遗留的东西<br>能够辅助 Android Studio 在项目的对应目录中存放注解处理器在编译期间生成的文件</p>
<p>####12. 使用<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">// 主工程的build.gradle</span><br><span class="line">buildscript &#123;</span><br><span class="line">    repositories &#123;</span><br><span class="line">      mavenCentral()</span><br><span class="line">    &#125;</span><br><span class="line">    dependencies &#123;</span><br><span class="line">        // replace with the current version of the Android plugin</span><br><span class="line">        classpath &apos;com.android.tools.build:gradle:1.3.0&apos;</span><br><span class="line">        // the latest version of the android-apt plugin</span><br><span class="line">        classpath &apos;com.neenbedankt.gradle.plugins:android-apt:1.8&apos;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">// 主Module的build.gradle</span><br><span class="line">apply plugin: &apos;com.android.application&apos;</span><br><span class="line">apply plugin: &apos;com.neenbedankt.android-apt&apos;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">dependencies &#123;</span><br><span class="line">// ...</span><br><span class="line">    compile project(&apos;:annotations&apos;)</span><br><span class="line">    apt project(&apos;:processors&apos;)</span><br><span class="line">//    compile project(&apos;:processors&apos;)</span><br><span class="line">//    compile project(&apos;:processors1&apos;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>####13. <a href="https://github.com/square/javapoet" target="_blank" rel="noopener">JavaPoet</a><br>在使用编译时注解时，需要在编译期间对注解进行处理，在这里我们没办法影响程序的运行逻辑，但我们可以进行一些需处理，比如生成一些功能性代码来辅助程序的开发，最常见的是生成<strong>.java</strong> 源文件，并在程序中可以调用到生成的文件。这样我们就可以用注解来帮助我们处理一些固定逻辑的重复性代码（如<a href="https://github.com/JakeWharton/butterknife" target="_blank" rel="noopener">butterknife</a>），提高开发的效率。</p>
<p>通过注解处理器来生成 <strong>.java</strong> 源文件基本上都会使用<a href="https://github.com/square/javapoet" target="_blank" rel="noopener">javapoet</a> 这个库，<strong>JavaPoet</strong>一个是用于产生 <strong>.java</strong> 源文件的辅助库，它可以很方便地帮助我们生成需要的<strong>.java</strong> 源文件，下面来看下具体使用方法。<br>使用如下代码进行依赖：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">compile &quot;com.squareup:javapoet:1.9.0&quot;</span><br></pre></td></tr></table></figure></p>
<p>####14. 注解生成器<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * 每一个注解处理器类都必须有一个空的构造函数，默认不写就行</span><br><span class="line"> */</span><br><span class="line">@AutoService(Processor.class)</span><br><span class="line">@SupportedSourceVersion(SourceVersion.RELEASE_7)</span><br><span class="line">@SupportedAnnotationTypes(&quot;com.mazaiting.CustomAnnotation&quot;)</span><br><span class="line">public class CustomProcessor extends AbstractProcessor&#123;</span><br><span class="line"></span><br><span class="line">    private Filer mFiler;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public synchronized void init(ProcessingEnvironment processingEnvironment) &#123;</span><br><span class="line">        super.init(processingEnvironment);</span><br><span class="line">        // Filter是个接口，至此吃通过注解处理器创建新文件</span><br><span class="line">        mFiler = processingEnvironment.getFiler();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public boolean process(Set&lt;? extends TypeElement&gt; set, RoundEnvironment roundEnvironment) &#123;</span><br><span class="line">        for (Element element : roundEnvironment.getElementsAnnotatedWith(CustomAnnotation.class)) &#123;</span><br><span class="line">            // 判断元素的类型为Class</span><br><span class="line">            if (element.getKind() == ElementKind.CLASS) &#123;</span><br><span class="line">                // 显示转换元素类型</span><br><span class="line">                TypeElement typeElement = (TypeElement) element;</span><br><span class="line">                // 输出元素名称</span><br><span class="line">//                System.out.println(typeElement.getSimpleName());</span><br><span class="line">//                // 输出注解属性值</span><br><span class="line">//                System.out.println(typeElement.getAnnotation(CustomAnnotation.class).value());</span><br><span class="line">                // 创建main方法</span><br><span class="line">                MethodSpec main =</span><br><span class="line">                        MethodSpec.methodBuilder(&quot;main&quot;)</span><br><span class="line">                                .addModifiers(Modifier.PUBLIC, Modifier.STATIC)</span><br><span class="line">                                .returns(void.class)</span><br><span class="line">                                .addParameter(String[].class, &quot;args&quot;)</span><br><span class="line">                                .addStatement(&quot;$T.out.println($S)&quot;, System.class, &quot;Hello, JavaPoet!&quot;)</span><br><span class="line">                                .build();</span><br><span class="line">                String value = element.getAnnotation(CustomAnnotation.class).value();</span><br><span class="line">                String first = value.substring(0, 1);</span><br><span class="line">                String className = first.toUpperCase() + value.substring(1, value.length());</span><br><span class="line">                TypeSpec valueClass =</span><br><span class="line">                        TypeSpec.classBuilder(className)</span><br><span class="line">                                .addModifiers(Modifier.PUBLIC, Modifier.FINAL)</span><br><span class="line">                                .addMethod(main)</span><br><span class="line">                                .build();</span><br><span class="line">                // 生成文件</span><br><span class="line">                try &#123;</span><br><span class="line">                    // 生成com.mazaiting.xxx.java</span><br><span class="line">                    JavaFile javaFile =</span><br><span class="line">                            JavaFile.builder(&quot;com.mazaiting.example&quot;, valueClass)</span><br><span class="line">                                    .addFileComment(&quot;This codes are generated automatically. Do not modify!&quot;)</span><br><span class="line">                                    .build();</span><br><span class="line">                    javaFile.writeTo(mFiler);</span><br><span class="line">                &#125; catch (IOException e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        return false;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>####15. MainActivity使用</p>
<pre><code>@CustomAnnotation(&quot;HelloWorld&quot;)
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

</code></pre><p>####16. 生成Java类<br>生成的Java类结构<br> <img src="http://upload-images.jianshu.io/upload_images/3110861-4a8aa7b8292d629e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图6.png"></p>

      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/blog/2018/08/06/Android/Android-自定义注解之源码注解(RetentionPolicy-SOURCE)/" rel="next" title="Android-自定义注解之源码注解(RetentionPolicy-SOURCE)">
                <i class="fa fa-chevron-left"></i> Android-自定义注解之源码注解(RetentionPolicy-SOURCE)
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/blog/2018/08/06/Android/Android-自定义注解之运行时注解(RetentionPolicy-RUNTIME)/" rel="prev" title="Android-自定义注解之运行时注解(RetentionPolicy-RUNTIME)">
                Android-自定义注解之运行时注解(RetentionPolicy-RUNTIME) <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      

      <section class="site-overview-wrap sidebar-panel sidebar-panel-active">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image"
                src="/blog/images/avatar.jpeg"
                alt="凌浩雨" />
            
              <p class="site-author-name" itemprop="name">凌浩雨</p>
              <p class="site-description motion-element" itemprop="description">专业从事于移动端开发，Android与iOS均有涉及，主做Android开发与React Native开发</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/blog/archives/">
              
                  <span class="site-state-item-count">393</span>
                  <span class="site-state-item-name">posts</span>
                </a>
              </div>
            

            

            

          </nav>

          

          

          
          

          
          

          

        </div>
      </section>

      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2018</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">凌浩雨</span>

  
</div>


  <div class="powered-by">Powered by <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a></div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">Theme &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Pisces</a> v5.1.4</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/blog/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/blog/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/blog/js/src/motion.js?v=5.1.4"></script>



  
  


  <script type="text/javascript" src="/blog/js/src/affix.js?v=5.1.4"></script>

  <script type="text/javascript" src="/blog/js/src/schemes/pisces.js?v=5.1.4"></script>



  
  <script type="text/javascript" src="/blog/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/blog/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/blog/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  












  





  

  

  

  
  

  

  

  

</body>
</html>
